use std::sync::{Arc, Mutex};

use interrupt::IntBackendDevice;

use super::{
    common::{
        GIC_INTERNAL, GIC_MAXIRQ, GIC_MAX_LR, GIC_NCPU, GIC_NCPU_VCPU, GIC_NR_APRS, GIC_NR_SGIS,
    },
    GICv2IrqState, GICv2StateInner, GICv2StateInterface,
};
use crate::GICv2State;

/// `GICv2` 构建器
#[derive(Default)]
pub struct GICv2StateBuilder {
    name: String,
    parent_irq: Option<[Arc<IntBackendDevice>; GIC_NCPU]>,
    parent_fiq: Option<[Arc<IntBackendDevice>; GIC_NCPU]>,
    parent_virq: Option<[Arc<IntBackendDevice>; GIC_NCPU]>,
    parent_vfiq: Option<[Arc<IntBackendDevice>; GIC_NCPU]>,
    maintenance_irq: Option<[Arc<IntBackendDevice>; GIC_NCPU]>,
}

impl GICv2StateBuilder {
    /// 创建一个构建器
    pub fn builder() -> Self {
        GICv2StateBuilder::default()
    }

    /// 设置名称
    pub fn set_name(mut self, name: &str) -> Self {
        self.name = String::from(name);
        self
    }

    /// 设置中断信号 irq
    pub fn set_irq(mut self, irq: &[Arc<IntBackendDevice>; GIC_NCPU]) -> Self {
        self.parent_irq = Some(irq.clone());
        self
    }

    /// 设置中断信号 fiq
    pub fn set_fiq(mut self, fiq: &[Arc<IntBackendDevice>; GIC_NCPU]) -> Self {
        self.parent_fiq = Some(fiq.clone());
        self
    }

    /// 设置中断信号 virq
    pub fn set_virq(mut self, virq: &[Arc<IntBackendDevice>; GIC_NCPU]) -> Self {
        self.parent_virq = Some(virq.clone());
        self
    }

    /// 设置中断信号 vfiq
    pub fn set_vfiq(mut self, vfiq: &[Arc<IntBackendDevice>; GIC_NCPU]) -> Self {
        self.parent_vfiq = Some(vfiq.clone());
        self
    }

    /// 设置中断信号 `maintenance_irq`
    pub fn set_maintenance_irq(mut self, irq: &[Arc<IntBackendDevice>; GIC_NCPU]) -> Self {
        self.maintenance_irq = Some(irq.clone());
        self
    }

    /// 构建 `GICv2State`
    ///
    /// # Panics
    /// 配置如果不符合预期将会 panic
    pub fn build(self) -> GICv2State {
        GICv2State {
            inner: Arc::new(Mutex::new(GICv2StateInner {
                ctlr: 0,
                cpu_ctlr: [0; GIC_NCPU_VCPU],
                irq_state: [GICv2IrqState::default(); GIC_MAXIRQ],
                irq_target: [0; GIC_MAXIRQ],
                priority1: [[0; GIC_NCPU]; GIC_INTERNAL],
                priority2: [0; GIC_MAXIRQ - GIC_INTERNAL],
                sgi_pending: [[0; GIC_NCPU]; GIC_NR_SGIS],
                priority_mask: [0; GIC_NCPU_VCPU],
                running_priority: [0; GIC_NCPU_VCPU],
                current_pending: [0; GIC_NCPU_VCPU],
                n_prio_bits: 8,
                bpr: [0; GIC_NCPU_VCPU],
                abpr: [0; GIC_NCPU_VCPU],
                apr: [[0; GIC_NCPU]; GIC_NR_APRS],
                nsapr: [[0; GIC_NCPU]; GIC_NR_APRS],
                h_hcr: [0; GIC_NCPU],
                h_misr: [0; GIC_NCPU],
                h_lr: [[0; GIC_NCPU]; GIC_MAX_LR],
                h_apr: [0; GIC_NCPU],
                num_lrs: 0,
                num_cpu: 1,
                num_irq: 32,
                revision: 1,
                security_extn: false,
                virt_extn: false,
                irq_reset_nonsecure: false,
            })),
            interface: GICv2StateInterface {
                parent_irq: self.parent_irq.unwrap(),
                parent_fiq: self.parent_fiq.unwrap(),
                parent_virq: self.parent_virq.unwrap(),
                parent_vfiq: self.parent_vfiq.unwrap(),
                maintenance_irq: self.maintenance_irq.unwrap(),
            },
            name: self.name,
        }
    }
}
